package com.eduagent.xwqeduagent.api.speechsynthesis.api;

import com.eduagent.xwqeduagent.api.speechsynthesis.api.constant.Constants;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import okhttp3.*;
import okio.ByteString;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.nio.charset.Charset;
import java.text.SimpleDateFormat;
import java.util.Base64;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;

/**
 * 讯飞超拟人语音合成服务
 */
public class SpeechSynthesisService extends WebSocketListener {
    private static final Gson gson = new Gson();
    private FileOutputStream fileOutputStream;
    private File outputFile;
    private String vcn; // 发音人参数
    private SpeechCallback callback;

    /**
     * 回调接口
     */
    public interface SpeechCallback {
        void onSuccess(File audioFile);
        void onError(int code, String message);
    }

    /**
     * 构造函数
     * @param outputFilePath 输出文件路径
     * @param voiceName 发音人参数
     * @param callback 回调函数
     */
    public SpeechSynthesisService(String outputFilePath, String voiceName, SpeechCallback callback) {
        try {
            this.outputFile = new File(outputFilePath);
            this.fileOutputStream = new FileOutputStream(outputFile);
            this.vcn = voiceName;
            this.callback = callback;
        } catch (Exception e) {
            if (callback != null) {
                callback.onError(-1, "初始化失败: " + e.getMessage());
            }
            e.printStackTrace();
        }
    }

    /**
     * 合成语音
     * @param text 待合成文本
     */
    public void synthesize(String text) {
        try {
            String ttsAuthUrl = getAuthUrl(Constants.HOST_URL, Constants.API_KEY, Constants.API_SECRET);
            OkHttpClient client = new OkHttpClient.Builder().build();
            // 将http://和https://分别替换为ws://和wss://
            String url = ttsAuthUrl.replace("http://", "ws://").replace("https://", "wss://");
            Request request = new Request.Builder().url(url).build();
            
            // 保存要合成的文本，在onOpen中使用
            this.textToSynthesize = text;
            
            // 建立WebSocket连接
            client.newWebSocket(request, this);
        } catch (Exception e) {
            if (callback != null) {
                callback.onError(-1, "合成请求失败: " + e.getMessage());
            }
            e.printStackTrace();
        }
    }

    // 存储要合成的文本
    private String textToSynthesize;

    @Override
    public void onOpen(WebSocket webSocket, Response response) {
        super.onOpen(webSocket, response);
        
        try {
            // 构建请求体
            JsonObject sendData = new JsonObject();
            JsonObject header = new JsonObject();
            JsonObject parameter = new JsonObject();
            JsonObject payload = new JsonObject();
            
            // 填充header
            header.addProperty("app_id", Constants.APP_ID);
            header.addProperty("status", 2); // 一次性合成，直接传2
            
            // 填充parameter - oral部分
            JsonObject oral = new JsonObject();
            oral.addProperty("oral_level", "mid");
            oral.addProperty("spark_assist", 1);
            
            // 填充parameter - tts部分
            JsonObject tts = new JsonObject();
            tts.addProperty("vcn", this.vcn); // 发音人
            tts.addProperty("speed", 50);
            tts.addProperty("volume", 50);
            tts.addProperty("pitch", 50);
            tts.addProperty("bgs", 0);
            tts.addProperty("reg", 0);
            tts.addProperty("rdn", 0);
            tts.addProperty("rhy", 0);
            
            // 填充audio参数
            JsonObject audio = new JsonObject();
            audio.addProperty("encoding", "lame");
            audio.addProperty("sample_rate", 24000);
            audio.addProperty("channels", 1);
            audio.addProperty("bit_depth", 16);
            audio.addProperty("frame_size", 0);
            
            tts.add("audio", audio);
            
            // 组合parameter
            parameter.add("oral", oral);
            parameter.add("tts", tts);
            
            // 填充payload - text部分
            JsonObject text = new JsonObject();
            text.addProperty("encoding", "utf8");
            text.addProperty("compress", "raw");
            text.addProperty("format", "plain");
            text.addProperty("status", 2); // 一次性合成
            text.addProperty("seq", 0);
            try {
                text.addProperty("text", Base64.getEncoder().encodeToString(textToSynthesize.getBytes("utf8")));
            } catch (UnsupportedEncodingException e) {
                if (callback != null) {
                    callback.onError(-1, "文本编码失败: " + e.getMessage());
                }
                throw new RuntimeException(e);
            }
            
            payload.add("text", text);
            
            // 组合最终请求
            sendData.add("header", header);
            sendData.add("parameter", parameter);
            sendData.add("payload", payload);
            
            // 发送请求
            webSocket.send(sendData.toString());
        } catch (Exception e) {
            if (callback != null) {
                callback.onError(-1, "发送请求失败: " + e.getMessage());
            }
            e.printStackTrace();
        }
    }

    @Override
    public void onMessage(WebSocket webSocket, String text) {
        super.onMessage(webSocket, text);
        
        // 处理返回数据
        System.out.println("接收到响应: " + text);
        JsonParse response = null;
        try {
            response = gson.fromJson(text, JsonParse.class);
        } catch (Exception e) {
            if (callback != null) {
                callback.onError(-1, "响应解析失败: " + e.getMessage());
            }
            e.printStackTrace();
            return;
        }
        
        // 检查响应码
        if (response.header.code != 0) {
            System.out.println("合成错误，错误码: " + response.header.code);
            System.out.println("本次会话ID: " + response.header.sid);
            if (callback != null) {
                callback.onError(response.header.code, "合成错误，会话ID: " + response.header.sid);
            }
            return;
        }
        
        // 处理音频数据
        if (response.payload != null && response.payload.audio != null && response.payload.audio.audio != null) {
            try {
                byte[] audioData = Base64.getDecoder().decode(response.payload.audio.audio);
                fileOutputStream.write(audioData);
                fileOutputStream.flush();
            } catch (Exception e) {
                if (callback != null) {
                    callback.onError(-1, "音频数据处理失败: " + e.getMessage());
                }
                e.printStackTrace();
            }
        }
        
        // 如果是最后一帧，关闭文件并回调
        if (response.header.status == 2) {
            try {
                fileOutputStream.close();
                System.out.println("合成完成，文件保存路径: " + outputFile.getPath());
                if (callback != null) {
                    callback.onSuccess(outputFile);
                }
            } catch (IOException e) {
                if (callback != null) {
                    callback.onError(-1, "文件关闭失败: " + e.getMessage());
                }
                e.printStackTrace();
            }
            webSocket.close(1000, "正常结束");
        }
    }

    @Override
    public void onMessage(WebSocket webSocket, ByteString bytes) {
        super.onMessage(webSocket, bytes);
    }

    @Override
    public void onClosing(WebSocket webSocket, int code, String reason) {
        super.onClosing(webSocket, code, reason);
        System.out.println("WebSocket即将关闭");
    }

    @Override
    public void onClosed(WebSocket webSocket, int code, String reason) {
        super.onClosed(webSocket, code, reason);
        System.out.println("WebSocket已关闭");
    }

    @Override
    public void onFailure(WebSocket webSocket, Throwable t, Response response) {
        super.onFailure(webSocket, t, response);
        System.out.println("连接失败");
        if (callback != null) {
            callback.onError(-1, "WebSocket连接失败: " + t.getMessage());
        }
    }

    /**
     * 签名鉴权加密
     */
    private static String getAuthUrl(String hostUrl, String apiKey, String apiSecret) throws Exception {
        URL url = new URL(hostUrl);
        SimpleDateFormat format = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US);
        format.setTimeZone(TimeZone.getTimeZone("GMT"));
        String date = format.format(new Date());
        StringBuilder builder = new StringBuilder("host: ").append(url.getHost()).append("\n").
                append("date: ").append(date).append("\n").
                append("GET ").append(url.getPath()).append(" HTTP/1.1");
        Charset charset = Charset.forName("UTF-8");
        Mac mac = Mac.getInstance("hmacsha256");
        SecretKeySpec spec = new SecretKeySpec(apiSecret.getBytes(charset), "hmacsha256");
        mac.init(spec);
        byte[] hexDigits = mac.doFinal(builder.toString().getBytes(charset));
        String sha = Base64.getEncoder().encodeToString(hexDigits);
        String authorization = String.format("hmac username=\"%s\", algorithm=\"%s\", headers=\"%s\", signature=\"%s\"", apiKey, "hmac-sha256", "host date request-line", sha);
        HttpUrl httpUrl = HttpUrl.parse("https://" + url.getHost() + url.getPath()).newBuilder().
                addQueryParameter("authorization", Base64.getEncoder().encodeToString(authorization.getBytes(charset))).
                addQueryParameter("date", date).
                addQueryParameter("host", url.getHost()).
                build();
        return httpUrl.toString();
    }

    /**
     * 响应JSON解析类
     */
    private static class JsonParse {
        Header header;
        Payload payload;
    }

    private static class Header {
        int code;
        String message;
        String sid;
        int status;
    }

    private static class Payload {
        Audio audio;
        Pybuf pybuf;
    }

    private static class Audio {
        String audio;
        int seq;
        int status;
    }

    private static class Pybuf {
        String text;
        int seq;
        int status;
    }
} 